﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;

namespace dx
{
    public partial class WinForm : Form
    {
        private Microsoft.DirectX.Direct3D.Device device;
        private System.ComponentModel.Container components = null;
        private float angle = 0f;

        private CustomVertex.PositionColored[] vertices;

        private VertexBuffer vb;
        private int[] indices;
        private IndexBuffer ib;

        private int[,] heightData;

        private Microsoft.DirectX.DirectInput.Device keyb;

        private int WIDTH = 64;
        private int HEIGHT = 64;

        public WinForm()
        {
            this.Width = 500;
            this.Height = 500;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
        }

        public void Initialize()
        {
            InitializeDevice();
            PlaceCamera();
            InitializeKeyboard();
            LoadHeightData();
            CreateTriangles();
            DeclareIndices();            
        }

        private void InitializeDevice()
        {
            PresentParameters presentParams = new PresentParameters();
            presentParams.Windowed = true;
            presentParams.SwapEffect = SwapEffect.Discard;

            device = new Microsoft.DirectX.Direct3D.Device(0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
        }

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            //angle += 0.05f;
            ReadKeyboard();
            
            device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);

            device.BeginScene();
            //device.Transform.World = Matrix.Translation(-HEIGHT / 2, -WIDTH / 2, 0) * Matrix.RotationAxis(new Vector3(angle, angle, 0), angle);
            device.Transform.World = Matrix.Translation(-HEIGHT / 2, -WIDTH / 2, 0) * Matrix.RotationZ(angle);

            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.SetStreamSource(0, vb, 0);
            device.Indices = ib;

            device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, WIDTH * HEIGHT, 0, indices.Length / 3);
            device.EndScene();

            device.Present();
            this.Invalidate();
        }

        private void PlaceCamera()
        {
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1f, 150f);
            device.Transform.View = Matrix.LookAtLH(new Vector3(0, -40, 50), new Vector3(0, -5, 0), new Vector3(0, 1, 0));
            device.RenderState.Lighting = false;
            //ver los dos lados del triangulo
            device.RenderState.CullMode = Cull.None;
            device.RenderState.FillMode = FillMode.WireFrame;
        }

        private void InitializeKeyboard()
        {
            keyb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
            keyb.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            keyb.Acquire();
        }

        private void ReadKeyboard()
        {
            KeyboardState keys = keyb.GetCurrentKeyboardState();
            if (keys[Key.Left])
            {
                angle += 0.03f;
            }
            if (keys[Key.Right])
            {
                angle -= 0.03f;
            }
        }

        private void LoadHeightData()
        {
            int offset;
            byte dummy;

            FileStream fs = new FileStream("heightmap.bmp", FileMode.Open, FileAccess.Read);
            BinaryReader r = new BinaryReader(fs);

            for (int i = 0; i < 10; i++)
            {
                dummy = r.ReadByte();
            }

            offset = r.ReadByte();
            offset += r.ReadByte() * 256;
            offset += r.ReadByte() * 256 * 256;
            offset += r.ReadByte() * 256 * 256 * 256;

            for (int i = 0; i < 4; i++)
            {
                dummy = r.ReadByte();
            }

            WIDTH = r.ReadByte();
            WIDTH += r.ReadByte() * 256;
            WIDTH += r.ReadByte() * 256 * 256;
            WIDTH += r.ReadByte() * 256 * 256 * 256;

            HEIGHT = r.ReadByte();
            HEIGHT += r.ReadByte() * 256;
            HEIGHT += r.ReadByte() * 256 * 256;
            HEIGHT += r.ReadByte() * 256 * 256 * 256;

            heightData = new int[WIDTH, HEIGHT];
            for (int i = 0; i < (offset - 26); i++)
            {
                dummy = r.ReadByte();
            }

            for (int i = 0; i < HEIGHT; i++)
            {
                for (int y = 0; y < WIDTH; y++)
                {
                    int height = (int)(r.ReadByte());
                    height += (int)(r.ReadByte());
                    height += (int)(r.ReadByte());
                    height /= 8;
                    heightData[WIDTH - 1 - y, HEIGHT - 1 - i] = height/20;
                }
            }
        }

        private void CreateTriangles()
        {
            vb = new VertexBuffer(typeof(CustomVertex.PositionColored), WIDTH * HEIGHT, device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);
            vertices = new CustomVertex.PositionColored[WIDTH * HEIGHT];

            for (int x = 0; x < WIDTH; x++)
            {

                for (int y = 0; y < HEIGHT; y++)
                {
                    //vertices[x + y * WIDTH].Position = new Vector3(x, y, 0);
                    vertices[x + y * WIDTH].Position = new Vector3(x, y, heightData[x, y]);
                    vertices[x + y * WIDTH].Color = Color.White.ToArgb();
                }
            }

            vb.SetData(vertices, 0, LockFlags.None);
        }

        private void DeclareIndices()
        {
            ib = new IndexBuffer(typeof(int), (WIDTH - 1) * (HEIGHT - 1) * 6, device, Usage.WriteOnly, Pool.Default);
            indices = new int[(WIDTH - 1) * (HEIGHT - 1) * 6];

            for (int x = 0; x < WIDTH - 1; x++)
            {

                for (int y = 0; y < HEIGHT - 1; y++)
                {
                    indices[(x + y * (WIDTH - 1)) * 6] = (x + 1) + (y + 1) * WIDTH;
                    indices[(x + y * (WIDTH - 1)) * 6 + 1] = (x + 1) + y * WIDTH;
                    indices[(x + y * (WIDTH - 1)) * 6 + 2] = x + y * WIDTH;

                    indices[(x + y * (WIDTH - 1)) * 6 + 3] = (x + 1) + (y + 1) * WIDTH;
                    indices[(x + y * (WIDTH - 1)) * 6 + 4] = x + y * WIDTH;
                    indices[(x + y * (WIDTH - 1)) * 6 + 5] = x + (y + 1) * WIDTH;
                }
            }
            ib.SetData(indices, 0, LockFlags.None);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }
    }
}
